#include "Timer.h"
#include "Logger.h"

using namespace ddserver::utility;
using namespace ddserver::thread;

void* timerWaiting(void *args)
{
    if(args == nullptr)
    {
        return nullptr; 
    }

    pTimer handle = (pTimer)args;
    struct epoll_event events[EPOLL_LISTEN_CNT];
    memset(events,0,sizeof(events));
    int fd_cnt = 0;

    while(1)
    {
        fd_cnt = epoll_wait(handle->epollfd,events,EPOLL_LISTEN_CNT,-1);
    
        for(int i = 0; i < fd_cnt; i++)
        {
            if (events[i].data.fd == handle->epollfd)
            {
                continue;
            }
            TimerItem* timer_item = (TimerItem*)events[i].data.ptr;
            uint64_t exp = 0;
            read(timer_item->timerfd,&exp,sizeof(exp));
            timer_item->func(timer_item->user_ctx);
        }
    }
}

Timer::Timer()
{
}

Timer::~Timer()
{
}

int Timer::start(unsigned int milli_time, int delay, PfnTimerHandlerCb cb, void *user_ctx)
{
    if(m_pTimer->timer_num > 128)
    {
        log_error("log_error:add timer_num=%d > 128",m_pTimer->timer_num);
        return -1;
    }

    if(cb == nullptr)
    {
        log_error("log_error:cb = nullptr");
        return -1;
    }

    int mydelay = delay < 50 ? 50:delay;
    int ret = 0;
    struct itimerspec timer_value;
    struct epoll_event event;
    pthread_t id;

    m_pTimer = (pTimer)malloc(sizeof(struct TagTimer));
    if(m_pTimer == nullptr)
    {
        log_error("log_error: m_pTimer nullptr");
        handleError();
        return -1;
    }
    bzero(m_pTimer,sizeof(struct TagTimer));
    m_pTimer->epollfd = epoll_create(EPOLL_LISTEN_CNT);
    if(m_pTimer->epollfd < 0)
    {
        log_error("log_error:epoll_create");
        handleError();
    }
    log_debug("epoll=%d",m_pTimer->epollfd);

    int timer_fd = timerfd_create(CLOCK_MONOTONIC,0);
    if(timer_fd < 0)
    {
        log_error("errno:timerfd_create");
        handleError();
    }
    m_pTimer->timer[m_pTimer->timer_num].timerfd = timer_fd;
    m_pTimer->timer[m_pTimer->timer_num].func = cb;
    m_pTimer->timer[m_pTimer->timer_num].user_ctx = user_ctx;

    //创建定时器
    timer_value.it_interval.tv_nsec = milli_time % 1000 * 1000000;
    timer_value.it_interval.tv_sec = milli_time / 1000;
    timer_value.it_value.tv_nsec = mydelay % 1000 * 1000000;
    timer_value.it_value.tv_sec = mydelay / 1000; 
    ret = timerfd_settime(m_pTimer->timer[m_pTimer->timer_num].timerfd,0,&timer_value,NULL);
    if (ret < 0)
    {
        log_error("log_error:timerfd_settime");
        handleError();
    }
    
    memset(&event,0,sizeof(event));
    event.data.fd = timer_fd;
    event.data.ptr = &m_pTimer->timer[m_pTimer->timer_num];
    event.events = EPOLLIN | EPOLLET;
    ret = epoll_ctl(m_pTimer->epollfd,EPOLL_CTL_ADD,timer_fd,&event);
    if(ret < 0)
    {   
        log_error("log_error:epoll_ctl");
        handleError();
    }

    id = pthread_create(&id,NULL,timerWaiting,m_pTimer);
  
    if (ret != 0)
    {
        log_error("log_error:eventTimedWait");
        handleError();
        return -1;
    }
    m_pTimer->timer_num++;

    return ret;
}

int Timer::add(unsigned milli_time, int delay, PfnTimerHandlerCb cb, void *user_ctx)
{
    if(m_pTimer->timer_num > 128)
    {
        log_error("log_error:add timer_num=%d > 128",m_pTimer->timer_num);
        return -1;
    }
    int ret = 0;
    struct itimerspec timer_value;
    struct epoll_event event;
    m_pTimer->timer[m_pTimer->timer_num].timerfd = timerfd_create(CLOCK_MONOTONIC,0);
    if (m_pTimer->timer[m_pTimer->timer_num].timerfd < 0)
    {
        log_error("errod:add log_error");
        handleError();
    }
    
    m_pTimer->timer[m_pTimer->timer_num].func = cb;
    m_pTimer->timer[m_pTimer->timer_num].user_ctx = user_ctx;

    // 创建定时器
    timer_value.it_interval.tv_nsec = milli_time % 1000 * 1000 * 1000;
    timer_value.it_interval.tv_sec = milli_time / 1000;
    timer_value.it_value.tv_nsec = delay % 1000 * 1000 * 1000;
    timer_value.it_value.tv_sec = delay / 1000;
    ret = timerfd_settime(m_pTimer->timer[m_pTimer->timer_num].timerfd, 0, &timer_value, NULL);
    if (ret < 0)
    {
        log_error("HTimerCreate: timerfd_settime failed");
        handleError();
        return -1;
    }

    memset(&event,0,sizeof(event));
    event.data.fd = m_pTimer->timer[m_pTimer->timer_num].timerfd;
    event.data.ptr = &m_pTimer->timer[m_pTimer->timer_num];
    event.events = EPOLLIN|EPOLLET;
    ret = epoll_ctl(m_pTimer->epollfd,EPOLL_CTL_ADD,m_pTimer->timer[m_pTimer->timer_num].timerfd,&event);
    if(ret < 0)
    {
        log_error("log_error:epoll_ctl log_error");
        handleError();
        return -1;
    }
    m_pTimer->timer_num++;
    return 0;
}

int Timer::stop()
{
    if (m_pTimer)
    {
        for(int i = 0 ; i < m_pTimer->timer_num ; i++)
        {
            if (m_pTimer->timer[m_pTimer->timer_num].timerfd > 0) 
            {
                close(m_pTimer->timer[m_pTimer->timer_num].timerfd);
            }
        }

        if (m_pTimer->epollfd > 0) 
        {
            close(m_pTimer->epollfd);
        }

        free(m_pTimer);
        m_pTimer = NULL;
    }
    return 0;
}

void Timer::handleError()
{
    if(m_pTimer)
    {
        if(m_pTimer->timer[m_pTimer->timer_num].timerfd > 0)
        {
            close(m_pTimer->timer[m_pTimer->timer_num].timerfd);
        }

        free(m_pTimer);
        m_pTimer = nullptr;
    }
}